package anatheme.parser;

import java.util.List;
import java.util.regex.MatchResult;

import javapop.framework.Grammar;
import javapop.framework.ParseContext;
import javapop.framework.Parser;
import javapop.framework.parser.BlockComment;
import javapop.framework.parser.Char;
import javapop.framework.parser.Choice;
import javapop.framework.parser.Forget;
import javapop.framework.parser.LineComment;
import javapop.framework.parser.ListOf;
import javapop.framework.parser.Literal;
import javapop.framework.parser.Many;
import javapop.framework.parser.Ref;
import javapop.framework.parser.Regexp;
import javapop.framework.parser.Space;
import javapop.framework.parser.XForm;
import javapop.framework.parser.tuple.One;
import javapop.framework.parser.tuple.Three;
import anatheme.ast.Expression;

public class AnathemeGrammar extends Grammar {

	public AnathemeGrammar() {
		createGrammar();
	}
	
	public void createGrammar() {
		Parser<?> spaces = new Forget(new Many<Character>(Space.getInstance())) {
			@Override
			public String getDescription() {
				return "<spaces>";
			}
		};
		register("spaces",spaces);
		
		Parser<String> lineComment = new LineComment(new Literal(";"));
		register("line-comment", lineComment);
		
		Parser<String> blockComment = new BlockComment(new Literal("%{"), new Literal("}%"));
		register("block-comment", blockComment);
		
		Parser<?> skip = new Forget(new Many<Object>(new Choice<Object>().either(ref("spaces"))
																		 .orElse(ref("block-comment"))
																		 .orElse(ref("line-comment")))) {
			@Override
			public String getDescription() {
				return "<skip>";
			}
		};
		register("skip", skip);
		
		Three<String, List<String>, Expression> define = new Three<String, List<String>, Expression>()
		.then(new Literal("define"))
		.then(ref("skip"))
		.first(new Ref<String>(this,"define-name"))
		.then(ref("skip"))
		.first(new Ref<String>(this,"define-params"))
		.then(ref("skip"))
		.first(new Ref<String>(this,"expression"));
		
		register("define", define);
		
		Parser<String> defineName = new XForm<MatchResult, String>(new Regexp("[a-zA-Z_\\.\\?\\!][a-zA-Z_\\.\\?\\!0-9]+")) {
			@Override
			public String transform(ParseContext<?> ctx,MatchResult content) {
				return content.group();
			}
		};		
		register("define-name", defineName);
		
		ListOf<String> defineParams = new ListOf<String>(
				/* child */ new XForm<MatchResult,String>(new Regexp("\\?[a-zA-Z]\\w+")) {
					@Override
					public String transform(ParseContext<?> ctx,MatchResult content) {
						return content.group();
					}
				})
				.first(new Char('('))
				.sep(new One<Character>().then(ref("skip")).parser(new Char(',')).then(ref("skip")))
				.last(new Char(')'));
		register("define-params", defineParams);
		
	}
	
}

